#include <cassert>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <string>
#include <vector>
int g_val = 0;
std::string func()
{
    return "我是一个独立的方法";
}
void *start_routine(void *args)
{
    const char *name = (const char *)args;
    while (true)
    {
        func();
        printf("我是新线程, 我正在运行, name : %s : %s : %d,&g_val : 0x%x\n", name, func().c_str(), g_val++, &g_val);
        sleep(1);
    }
    return nullptr;
}
void test()
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, start_routine, (void *)"thread one");
    assert(n == 0);
    (void)n;
    while (true)
    {
        printf("我是主线程, 我正在运行, 我创建出来的新线程tid : 0x%x : %s : %d , &g_val : 0x%x\n", tid, func().c_str(), g_val, &g_val);
        sleep(1);
    }
}
void *start_routine1(void *args)
{
    std::string name = static_cast<const char *>(args);
    while (true)
    {
        printf("new thread create success, name: %s\n", name.c_str());
        sleep(1);
        // int *p = nullptr;
        // *p = 0;
    }
}
void test1()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, start_routine1, (void *)"thread one");
    while (true)
    {
        printf("new thread create success, name: main thread\n");
        sleep(1);
    }
}
void test2()
{
#define NUM 10
    for (int i = 0; i < NUM; i++)
    {
        pthread_t tid;
        char namebuffer[64];
        snprintf(namebuffer, sizeof(namebuffer), "%s : %d", "thread", i);
        pthread_create(&tid, nullptr, start_routine1, (void *)namebuffer);
    }
    while (true)
    {
        printf("new thread create success, name: main thread\n");
        sleep(1);
    }
}
class ThreadData
{
public:
    int number;
    pthread_t tid;
    char namebuffer[64];
};
void *start_routine2(void *args)
{
    sleep(1);
    ThreadData *td = static_cast<ThreadData *>(args);
    int cnt = 10;
    while (cnt)
    {
        printf("cnt : %d, &cnt : 0x%x\n", cnt, &cnt);
        cnt--;
        sleep(1);
    }
    pthread_exit((void *)td->number);
}
void test3()
{
    std::vector<ThreadData *> threads;
#define NUN 10
    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();
        td->number = i + 1;
        snprintf(td->namebuffer, sizeof(td->namebuffer), "%s : %d", "thread", i);
        pthread_create(&td->tid, nullptr, start_routine2, (void *)td);
        threads.push_back(td);
    }
    for (auto &iter : threads)
    {
        printf("create thread : %s : %d success..\n", iter->namebuffer, iter->tid);
    }
    for (auto &iter : threads)
    {
        void *ret = nullptr;
        int n = pthread_join(iter->tid, &ret);
        assert(n == 0);
        printf("join : %s success, number : %lld\n", iter->namebuffer, (long long)ret);
        delete iter;
    }
    printf("main thread quit\n");
}
void *start_routine3(void *args)
{
    sleep(1);
    ThreadData *td = static_cast<ThreadData *>(args);
    int cnt = 10;
    while (cnt)
    {
        printf("cnt : %d, &cnt : 0x%x\n", cnt, &cnt);
        cnt--;
        sleep(1);
    }
    return (void *)100;
}
void test4()
{
    std::vector<ThreadData *> threads;
#define NUN 10
    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();
        td->number = i + 1;
        snprintf(td->namebuffer, sizeof(td->namebuffer), "%s : %d", "thread", i);
        pthread_create(&td->tid, nullptr, start_routine3, (void *)td);
        threads.push_back(td);
    }
    for (auto &iter : threads)
    {
        printf("create thread : %s : %d success..\n", iter->namebuffer, iter->tid);
    }
    sleep(5);
    for (int i = 0; i < threads.size() / 2; i++)
    {
        pthread_cancel(threads[i]->tid);
        printf("pthread_cancel : %s : %d success...\n", threads[i]->namebuffer, threads[i]->tid);
    }
    for (auto &iter : threads)
    {
        void *ret = nullptr;
        int n = pthread_join(iter->tid, &ret);
        assert(n == 0);
        printf("join : %s success, exit_code : %lld\n", iter->namebuffer, (long long)ret);
        delete iter;
    }
    printf("main thread quit\n");
}
std::string changeid(const pthread_t &thread_id)
{
    char tid[128];
    snprintf(tid, sizeof(tid), "0x%x", thread_id);
    return tid;
}
void *start_routine4(void *args)
{
    std::string threadname = static_cast<const char *>(args);
    int cnt = 5;
    while (cnt--)
    {
        printf("%s running... : %s\n", threadname.c_str(), changeid(pthread_self()).c_str());
        sleep(1);
    }
    return nullptr;
}
void test5()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, start_routine4, (void *)"thread 1");
    std::string mainid = changeid(pthread_self());
    pthread_detach(tid);
    printf("main thread running...new thread id : %s, main thread id : %s\n", changeid(tid).c_str(), mainid.c_str());
    sleep(2);
    int n = pthread_join(tid, nullptr);
    printf("result : %d, %s\n", n, strerror(n));
}
__thread int g_val1 = 100;
void *start_routine5(void *args)
{
    std::string threadname = static_cast<const char *>(args);
    int cnt = 5;
    while (true)
    {
        printf("%s running ... : %s g_val1 : %d &g_val1 : 0x%x\n",
               threadname.c_str(), changeid(pthread_self()).c_str(), g_val1, &g_val1);
        sleep(1);
        g_val1++;
    }
    return nullptr;
}
void test6()
{
    pthread_t tid,uid;
    pthread_create(&tid, nullptr, start_routine5, (void *)"thread 1");
    pthread_create(&uid, nullptr, start_routine5, (void *)"thread 2");
    std::string main_id = changeid(pthread_self());
    pthread_detach(tid);
    pthread_detach(uid);
    printf("main thread running ... new thread id : %s  main thread id : %s\n", changeid(tid).c_str(), main_id.c_str());
    printf("main thread running ... new thread id : %s  main thread id : %s\n", changeid(uid).c_str(), main_id.c_str());
    while (true)
    {
        printf("main thread running ... new thread id : %s  main thread id : %s g_val1 : %d &g_val1 : 0x%x\n",
               changeid(tid).c_str(), main_id.c_str(), g_val1, &g_val1);
        printf("main thread running ... new thread id : %s  main thread id : %s g_val1 : %d &g_val1 : 0x%x\n",
               changeid(uid).c_str(), main_id.c_str(), g_val1, &g_val1);
        sleep(1);
    }
}
int main()
{
    // test();
    // test1();
    // test2();
    // test3();
    // test4();
    // test5();
    test6();
    return 0;
}